package action

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/logger"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	"ssdevice/common/enums"
	"ssdevice/common/middleware/mqtt"
	"ssdevice/common/utils"
	"ssdevice/internal/data/format"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/service"
)

type Login struct {
	Orm *gorm.DB
}

func (action *Login) Execute(topic string, jsonData map[string]interface{}) {
	devSn := strings.Split(topic, "/")[3]
	gateSn, devType, to := format.GetFromTo(devSn, jsonData, true)
	if len(devType) == 0 {
		// 异常
		ackTopic := fmt.Sprintf("/iot/%s/%s/%s/ack", gateSn, constant.TopicPlaceholder, enums.Login.Get().Name)
		ackData := map[string]interface{}{
			"sid":  jsonData["sid"],
			"from": constant.TopicPlaceholder,
			"to":   to,
			"code": 500,
			"msg":  "platform db error",
			"data": map[string]interface{}{
				"ak":   "",
				"goto": "",
			},
		}
		mqtt.MqttClient.Publish(ackTopic, utils.MapToBytes(ackData))
		return
	}
	jsonData[constant.CacheLoginInfo] = map[string]interface{}{
		constant.CacheDevSn:   devSn,
		constant.CacheGateSn:  gateSn,
		constant.CacheDevType: devType,
		constant.CacheFrom:    gateSn,
		constant.CacheTo:      to,
	}
	if err := env.Cache.LPush(constant.DeviceLoginCacheQueue, string(utils.MapToBytes(jsonData))); err != nil {
		logger.Errorf("登录消息队列lpush err:%s", err.Error())
	}
}

// 1、登录消息顺序消费
// 2、登录消息来源：设备登录包、平台自判断
func (action *Login) Run(threadName string) {
	go func() {
		for {
			select {
			case <-time.After(time.Second):
				result, _ := env.Cache.BRPop(time.Second*10, constant.DeviceLoginCacheQueue)
				if len(result) >= 2 {
					action.Login(utils.BytesToMap([]byte(result[1])))
				}
			}
		}
	}()
}

// 登录业务处理
func (action *Login) Login(jsonData map[string]interface{}) {
	cacheInfo := jsonData[constant.CacheLoginInfo].(map[string]interface{})
	devSn := cacheInfo[constant.CacheDevSn].(string)
	gateSn := cacheInfo[constant.CacheGateSn].(string)
	devType := cacheInfo[constant.CacheDevType].(string)
	from := cacheInfo[constant.CacheFrom].(string)
	to := cacheInfo[constant.CacheTo].(string)
	// 初始化判断
	theDev := action.initDevice(devSn, gateSn, devType, jsonData, from)
	// 更新状态
	dev := &models.SysDev{}
	dev.Model.Orm = action.Orm
	if err := dev.UpdateOnlineStatus(devSn, map[string]interface{}{
		"online_status":  enums.Online,
		"last_live_time": time.Now(),
	}); err != nil {
		logger.Error(err)
	}
	// goto获取
	goTo := ""
	if len(theDev.Id) > 0 {
		goTo = format.GetLoginRedirectAddr(action.Orm, theDev)
	}
	// 响应
	logInOutAck(gateSn, to, enums.Login.Get().Name, jsonData, goTo)
}

// 初始化(不存在的设备)
func (action *Login) initDevice(devSn, gateSn, devType string, jsonData map[string]interface{}, from string) (theDev models.SysDev) {
	// 暂不初始网关(下位机先login初始网关时，无法确认网关类型)
	//if devType == enums.DevTypeOfDevice && devSn != gateSn {
	//	// 设备的话,初始化网关判断
	//	action.initDevice(gateSn, gateSn, enums.DevTypeOfGateway, map[string]interface{}{})
	//}

	var err error
	// 平台自登录已判断设备不存在
	if from != constant.TopicPlaceholder {
		dev := &models.SysDev{}
		dev.Model.Orm = action.Orm
		theDev, err = dev.FindDeviceBySn(devSn)
		// 存在
		if err != nil || len(theDev.Id) > 0 {
			return
		}
	}
	// 不存在
	devService := &service.Device{}
	devService.Orm = action.Orm
	devService.SetAllModel()
	addReq := command.DeviceInsertReq{
		Sn:            devSn,
		Name:          devSn,
		ProductModel:  "",
		Location:      nil,
		SoftCmd:       "",
		FromLoginInit: true,
	}
	addReq.Type = devType
	if devType == enums.DevTypeOfDevice && devSn != gateSn {
		addReq.GatewaySn = gateSn
	}
	// 按产品初始
	productModel := utils.GetFieldFromJson([]string{"data", "model"}, jsonData)
	if productModel != nil {
		addReq.ProductModel = productModel.(string)
	}
	logger.Infof("初始化接入设备[%s]-类型[%s]", devSn, addReq.Type)
	if err, theDev = devService.AddDevice(&addReq); err != nil {
		logger.Error(err)
	}
	return
}

// 平台自动登录，数据包里没有from/to、设备类型判断如准确，页面手动修改
func AutoLogin(db *gorm.DB, devSn string, jsonData map[string]interface{}) (gateSn, devType, to string) {
	devCache, _ := env.Cache.HashGet(constant.DeviceEasyCache, devSn)
	if len(devCache) > 0 {
		// 设备存在
		return
	}
	// 设备不存在，自动登录
	devType = enums.DevTypeOfDevice
	// 默认是device类型,from数据判断
	if from, ok := jsonData["from"]; ok && from != nil && len(from.(string)) > 0 {
		if from.(string) != devSn {
			gateSn = from.(string)
			to = devSn
		} else {
			devType = enums.DevTypeOfGateway
			gateSn = devSn
		}
	} else {
		gateSn = devSn
	}
	// 登录消费队列
	loginData := map[string]interface{}{
		"sid": -1,
		constant.CacheLoginInfo: map[string]interface{}{
			constant.CacheDevSn:   devSn,
			constant.CacheGateSn:  gateSn,
			constant.CacheDevType: devType,
			constant.CacheFrom:    gateSn,
			constant.CacheTo:      to,
		},
	}
	loginAction := &Login{Orm: db}
	loginAction.Login(loginData)
	return
}
